package com.tarena.lbs.content.service.impl;

import com.tarena.lbs.content.pojo.vo.ArticleStatsVO;
import com.tarena.lbs.content.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class RedisServiceImpl implements RedisService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final String ARTICLE_STATS_KET_PREFIX="article:stats";
    public static final String FIELD_LIKE_COUNT ="likeCount";
    public static final String FIELD_FAVORITE_COUNT ="favoriteCount";
    public static final String FIELD_ASSESS_COUNT="accessCount";
    private static final long ARTICLE_STATS_EXPIRE_SECONDS=1800l;


    @Override
    public void deleteArticleStats(String articleId) {

    }
    @Override
    public void refillBatchArticleStats(Map<String, ArticleStatsVO> statsMap) {

    }

    private String buildKey(String articleId){
        return ARTICLE_STATS_KET_PREFIX+articleId;
    }

    @Override
    public void incrementArticleStat(String articleId, String field, long value){
        String key=buildKey(articleId);

        stringRedisTemplate.executePipelined((RedisCallback<Object>)connection-> {
            connection.hashCommands().hIncrBy(key.getBytes(),field.getBytes(),value);

            connection.keyCommands().expire(key.getBytes(), ARTICLE_STATS_EXPIRE_SECONDS);

            return null;
        });

    }
    @Override
    public ArticleStatsVO getArticleStats(String articleId){
        Map<Object,Object>entries=stringRedisTemplate.opsForHash().entries(buildKey(articleId));
        if(entries==null || entries.isEmpty()){
            return null;
        }
        return mapToStatsVO(entries);
    }

    private ArticleStatsVO mapToStatsVO(Map<Object, Object> entries) {
        return null;
    }

    @Override
    public Map<String,ArticleStatsVO>getBatchArticleStats(List<String> articleIds){
        if(articleIds==null || articleIds.isEmpty()){
            return new HashMap<>();
        }
        List<Object>results=stringRedisTemplate.executePipelined((RedisCallback<Object>)connection->{
            for(String articleId:articleIds){
                String s = buildKey(articleId.getBytes().toString());
                connection.hashCommands().hGetAll(s.getBytes());
            }
            return null;
                });


                Map<String,ArticleStatsVO>statsMap =new HashMap<>();
               for(int i=0;i<articleIds.size();i++){
                   Map<Object,Object>entries=(Map<Object, Object>) results.get(i);
                   if(entries !=null && !entries.isEmpty()){
                       statsMap.put(articleIds.get(i),mapToStatsVO(entries));
                }
            }
               return statsMap;
        }
        @Override
    public void refillArticleStats(String articleId, ArticleStatsVO stats){
        log.debug("缓存未命中,正在回填：{}",articleId);
        if(articleId ==null || stats ==null){
            return;
        }

        String key=buildKey(articleId);

        stringRedisTemplate.executePipelined((RedisCallback<Object>) (RedisConnection connection) ->{
            Map<byte[],byte[]>hashes=new HashMap<>();
            hashes.put(FIELD_LIKE_COUNT.getBytes(),String.valueOf(stats.getLikeCount()).getBytes());
            hashes.put(FIELD_FAVORITE_COUNT.getBytes(),String.valueOf(stats.getFavoriteCount()).getBytes());
            hashes.put(FIELD_ASSESS_COUNT.getBytes(),String.valueOf(stats.getAccessCount()).getBytes());

            connection.hashCommands().hMSet(key.getBytes(),hashes);
            connection.keyCommands().expire(key.getBytes(),ARTICLE_STATS_EXPIRE_SECONDS);

            return null;
        });

//        @Override
//            public void refillBatchArticleStats(Map<String,ArticleStatsVO> statsMap){
//                if(statMap ==null || statMap.isEmpty()){
//                    return;
//                }
//                stringRedisTemplate.executePipelined(RedisCallback<Object>)connection->{
//                    for(Map.Entry<String,ArticleStatsVO> entry: statsMap.entrySet()){
//                        String key=buildKey(entry.getKey());
//                        ArticleStatsVO stats = entry.getValue();
//                        String key =buildKey(articleId);
//
//                        Map<byte[],byte[]>hashes=new HashMap<>();
//                        hashes.put(FIELD_ASSESS_COUNT.getBytes(),String.valueOf(stats.getLikeCount()).getBytes());
//                        hashes.put(FIELD_FAVORITE_COUNT.getBytes(),String.valueOf(stats.getFavoriteCount()).getBytes());
//                        hashes.put(FIELD_LIKE_COUNT.getBytes(),String.valueOf(stats.getAccessCount()).getBytes());
//
//                        connection.hashCommands().hMSet(key.getBytes(),hashes);
//                        connection.keyCommands().expire(key.getBytes(),ARTICLE_STATS_EXPIRE_SECONDS);
//                    }
//                    return null;
//                    });
//            }
//            @Override
//            public void deleteArticleStats(String articleId){
//                stringRedisTemplate.delete(buildKey(articleId));
//            }
//            private ArticleStatsVO mapToStatsVO(Map<Object,Object> entries){
//            ArticleStatsVO stats=new ArticleStatsVO();
//            if(entries !=null && !entries.isEmpty()){
//                return stats;
//            }
//            try{
//                stats.setLikeCount(Integer.parseInt(entries.getOrDefault(FIELD_LIKE_COUNT,0).toString()));
//                stats.setFavoriteCount(Integer.parseInt(entries.getOrDefault(FIELD_FAVORITE_COUNT,0).toString()));
//                stats.setAccessCount(Integer.parseInt(entries.getOrDefault(FIELD_ASSESS_COUNT,0).toString()));
//            }catch (NumberFormatException e){
//
//            }
//            return stats;
//            }
    }
}
